package com.tarena.test.redis.demo;

import com.tarena.redis.demo.RedisDemoStarter;
import com.tarena.redis.demo.service.StockService;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

@SpringBootTest(classes= RedisDemoStarter.class)
@Slf4j
public class RedisLockDemo {
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private StockService stockService;
    //补充分布式锁的设计流程
    @Test
    public void reduceTest01(){
        log.info("version1 版本抢锁逻辑");
        //1.设计key值 和抢锁
        String id="1";
        String keyLock="lock"+id;
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        //setnx setIfAbsent
        Boolean tryLock = operations.setIfAbsent(keyLock, "");
        //2.判断
        if(tryLock){
            log.info("当前线程:{},抢锁key:{},成功",Thread.currentThread().getId(),keyLock);
            //true 当前线程抢到锁了
            stockService.reduceStock("1");
        }
    }
    //version2版本分布式锁
    @Test
    public void reduceTest02(){
        log.info("version2 版本抢锁逻辑");
        //1.设计key值 和抢锁
        String id="1";
        String keyLock="lock"+id;
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        //setnx setIfAbsent
        Boolean tryLock = operations.setIfAbsent(keyLock, "");
        //2.判断
        while(!tryLock){
            //while循环 只要没抢到
            log.info("当前抢锁失败 等待5秒继续抢锁,线程:{}",Thread.currentThread().getId());
            try{
                Thread.sleep(5000);
            }catch (Exception e){
                log.error("线程等待 被打断");
            }
            tryLock=operations.setIfAbsent(keyLock, "");
        }
        try{
            log.info("当前线程:{},抢锁key:{},成功",Thread.currentThread().getId(),keyLock);
            stockService.reduceStock("1");
        }catch (Exception e){
            log.error("业务执行失败,当前线程:{}",Thread.currentThread().getId(),e);
        }finally {
            redisTemplate.delete(keyLock);
        }

    }
    @Test
    public void reduceTest03(){
        log.info("version3 版本抢锁逻辑");
        //1.设计key值 和抢锁
        String id="1";
        String keyLock="lock"+id;
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        //setnx setIfAbsent
        Boolean tryLock = operations.setIfAbsent(keyLock, "",10, TimeUnit.SECONDS);
        //2.判断
        while(!tryLock){
            //while循环 只要没抢到
            log.info("当前抢锁失败 等待5秒继续抢锁,线程:{}",Thread.currentThread().getId());
            try{
                Thread.sleep(5000);
            }catch (Exception e){
                log.error("线程等待 被打断");
            }
            tryLock=operations.setIfAbsent(keyLock, "");
        }
        try{
            log.info("当前线程:{},抢锁key:{},成功",Thread.currentThread().getId(),keyLock);
            stockService.reduceStock("1");
        }catch (Exception e){
            log.error("业务执行失败,当前线程:{}",Thread.currentThread().getId(),e);
        }finally {
            redisTemplate.delete(keyLock);
        }
    }
    @Test
    public void reduceTest04(){
        log.info("version4 版本抢锁逻辑");
        //1.设计key值 和抢锁
        String id="1";
        String keyLock="lock"+id;
        String uuid= UUID.randomUUID().toString();
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        //setnx setIfAbsent
        Boolean tryLock = operations.setIfAbsent(keyLock, uuid,10, TimeUnit.SECONDS);
        //2.判断
        while(!tryLock){
            //while循环 只要没抢到
            log.info("当前抢锁失败 等待5秒继续抢锁,线程:{}",Thread.currentThread().getId());
            try{
                Thread.sleep(5000);
            }catch (Exception e){
                log.error("线程等待 被打断");
            }
            tryLock=operations.setIfAbsent(keyLock, "");
        }
        try{
            log.info("当前线程:{},抢锁key:{},成功",Thread.currentThread().getId(),keyLock);
            stockService.reduceStock("1");
        }catch (Exception e){
            log.error("业务执行失败,当前线程:{}",Thread.currentThread().getId(),e);
        }finally {
            String redisValue = operations.get(keyLock);
            if (uuid.equals(redisValue)) {
                log.info("当前数据和随机码相同 是同一把锁 删除");
                redisTemplate.delete(keyLock);
            }else{
                log.info("当前数据和随机码不同 不同一把锁 不删除");
            }
        }
    }
}
